package com.zjt.smart.mvp.view;

import android.support.annotation.Nullable;

import com.zjt.smart.api.server.BaseServer;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * 并发加载LoadView
 * 只有当所有Loader执行完成才会走到onSuccess获取onCache
 */

public class ParallelLoadView implements LoadView<Object> {
    private LoadView<Object> loadView;
    private List<ParallelLoader> list;
    private HashMap<ParallelLoader, Status> taskStatus;
    private enum Status {WAITING, SUCCESS, FAIL}
    private List<Object> result;
    private long cacheTime = 0;

    public ParallelLoadView(LoadView<Object> loadView) {
        this.loadView = loadView;
        list = new ArrayList<>();
        result = new ArrayList<>();
        taskStatus = new HashMap<>();
    }

    public void addLoader(ParallelLoader loader) {
        list.add(loader);
    }

    public void startLoading(boolean fromCache) {
        taskStatus.clear();
        result.clear();
        cacheTime = 0;
        for (ParallelLoader loader : list) {
            setTaskStatus(loader, Status.WAITING);
        }
        for (ParallelLoader loader : list) {
            executeLoader(loader, fromCache);
        }
    }

    private void executeLoader(ParallelLoader loader, boolean fromCache) {
        LoadView<Object> parallelLoadView = new LoadView<Object>() {
            @Nullable
            @Override
            public void onSuccess(List<Object> data) {
                addData(data);
                setTaskStatus(loader, Status.SUCCESS);
                checkResult(fromCache);
            }

            @Override
            public void onCache(long cacheTime, List<Object> data) {
                if (cacheTime == 0) {
                    setTaskStatus(loader, Status.FAIL);
                    checkResult(fromCache);
                    return;
                }
                addData(data);
                if (cacheTime > ParallelLoadView.this.cacheTime) {
                    ParallelLoadView.this.cacheTime = cacheTime;
                }
                setTaskStatus(loader, Status.SUCCESS);
                checkResult(fromCache);
            }

            @Override
            public void onFail(int errorCode, String errorMsg) {
                if (errorCode == BaseServer.NO_MORE) {
                    setTaskStatus(loader, Status.SUCCESS);
                } else {
                    setTaskStatus(loader, Status.FAIL);
                }
                checkResult(fromCache);
            }
        };
        loader.loadParallel(parallelLoadView, fromCache);
    }

    private synchronized void addData(List<Object> data) {
        if (data == null || data.size() == 0) {
            return;
        }
        result.addAll(data);
    }

    private synchronized void setTaskStatus(ParallelLoader loader, Status status) {
        taskStatus.put(loader, status);
    }

    private void checkResult(boolean fromCache) {
        //检查是否完成
        for (Status status : taskStatus.values()) {
            if (status == Status.WAITING) {
                return;
            }
        }
        //检查是否存在加载失败
        for (Status status : taskStatus.values()) {
            if (status == Status.FAIL) {
                if (fromCache) {
                    onCache(0, null);
                } else {
                    onFail(BaseServer.DATA_INCOMPLETE, "Data incomplete in parallel request");
                }
                return;
            }
        }
        if (fromCache) {
            onCache(cacheTime, result);
        } else {
            onSuccess(result);
        }

    }

    @Nullable
    @Override
    public void onSuccess(List<Object> data) {
        if (loadView != null) {
            loadView.onSuccess(data);
        }
    }

    @Override
    public void onCache(long cacheTime, List<Object> data) {
        if (loadView != null) {
            loadView.onCache(cacheTime, data);
        }
    }

    @Override
    public void onFail(int errorCode, String errorMsg) {
        if (loadView != null) {
            loadView.onFail(errorCode, errorMsg);
        }
    }

    public interface ParallelLoader<ParallelType> extends Loader {

        void loadParallel(LoadView<ParallelType> loadView, boolean fromCache);
    }


}
